package com.dmitriyp.movie.implementation;

import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.dmitriyp.movie.mapping.Format;
import com.dmitriyp.movie.mapping.Movie;

/**
 * Class for parsing Movies from xml file;
 * 
 * @author Dmitriy
 * 
 */
public class MovieImporter {

	private final static String MOVIE = "movie", TITLE = "title",
			FORMAT = "format", YEAR = "release_year", STAR = "star",
			STARS = "stars";

	private List<Movie> list = new LinkedList<Movie>();
	private final String file;

	/**
	 * @param file
	 *            - xml file that contains movies
	 */
	public MovieImporter(String file) {
		this.file = file;
	}

	/**
	 * Parses file and returns List of the movies from this file
	 * 
	 * @return
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 */
	public List<Movie> getMovies()
			throws ParserConfigurationException,
			SAXException,
			IOException {
		list.clear();
		SAXParserFactory factory = SAXParserFactory.newInstance();
		SAXParser saxParser = factory.newSAXParser();
		saxParser.parse(file, handler);
		return list;
	}

	private DefaultHandler handler = new DefaultHandler() {

		private boolean inMovie, inTitle, inYear, inStars, inStar, inFormat;
		private Movie current;

		@Override
		public void startElement(String uri, String localName, String qName,
				Attributes attributes) throws SAXException {
			if (MOVIE.equals(qName)) {
				inMovie = true;
				current = new Movie();
			} else if (TITLE.equals(qName)) {
				inTitle = true;
			} else if (FORMAT.equals(qName)) {
				inFormat = true;
			} else if (YEAR.equals(qName)) {
				inYear = true;
			} else if (STAR.equals(qName)) {
				inStar = true;
			} else if (STARS.equals(qName) && inMovie) {
				inStars = true;
				current.setStars(new HashSet<String>());
			}
		}

		@Override
		public void endElement(String uri, String localName, String qName)
				throws SAXException {
			if (MOVIE.equals(qName)) {
				if (inMovie) {
					list.add(current);
					inMovie = false;
					current = null;
				}
			} else if (TITLE.equals(qName)) {
				inTitle = false;
			} else if (FORMAT.equals(qName)) {
				inFormat = false;
			} else if (YEAR.equals(qName)) {
				inYear = false;
			} else if (STAR.equals(qName)) {
				inStar = false;
			} else if (STARS.equals(qName)) {
				inStars = false;
			}
		}

		@Override
		public void characters(char[] ch, int start, int length)
				throws SAXException {
			String value = new String(ch, start, length).trim();
			if (!inMovie)
				return;

			if (inTitle) {
				current.setTitle(value);
			} else if (inFormat) {
				Format format = Format.getFormat(value);
				current.setFormat(format);
			} else if (inYear) {
				try {
					int year = Integer.parseInt(value);
					current.setReleaseYear(year);
				} catch (NumberFormatException ex) {
					inMovie = false;
					inYear = false;
					current = null;
				}
			} else if (inStar && inStars) {
				current.getStars().add(value);
			}
		}
	};
}
